package com.zero.manage.web.components.service.impl;


import cn.hutool.core.util.StrUtil;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQuery;
import com.zero.manage.web.components.base.BaseService;
import com.zero.manage.web.components.dao.SysPowerDao;
import com.zero.manage.web.components.entity.rbac.*;
import com.zero.manage.web.components.query.SysPowerQuery;
import com.zero.manage.web.components.service.SysPowerService;
import com.zero.manage.web.components.vo.SysPowerVO;
import com.zero.manage.web.utils.CommonConst;
import com.zero.manage.web.utils.CommonUtils;
import io.gitee.zerowsh.constant.ToolConstant;
import io.gitee.zerowsh.enums.ResultEnums;
import io.gitee.zerowsh.enums.ToolEnums;
import io.gitee.zerowsh.util.PublicResult;
import io.gitee.zerowsh.util.TreeNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


@Service
@Slf4j
public class SysPowerServiceImpl extends BaseService<SysPowerEntity, String, SysPowerDao, SysPowerQuery> implements SysPowerService {
    private QSysPowerEntity qSysPowerEntity = QSysPowerEntity.sysPowerEntity;
    private QSysUserEntity qSysUserEntity = QSysUserEntity.sysUserEntity;
    private QSysUserRoleEntity qSysUserRoleEntity = QSysUserRoleEntity.sysUserRoleEntity;
    private QSysRoleEntity qSysRoleEntity = QSysRoleEntity.sysRoleEntity;
    private QSysRolePowerEntity qSysRolePowerEntity = QSysRolePowerEntity.sysRolePowerEntity;


    @Autowired
    private ShiroFilterFactoryBean shiroFilterFactoryBean;

    @Override
    public PublicResult<List<SysPowerVO>> tree(ToolEnums.PowerTypeEnums type) {
        JPAQuery<SysPowerVO> from = jpa.select(new SysPowerVO().initQBean(qSysPowerEntity)).from(qSysPowerEntity);
        if (Objects.nonNull(type)) {
            if (Objects.equals(type, ToolEnums.PowerTypeEnums.POWER)) {
                //权限--查询目录和菜单
                from.where(qSysPowerEntity.type.in(ToolEnums.PowerTypeEnums.CATALOG, ToolEnums.PowerTypeEnums.MENU));
            } else {
                //菜单、目录、其他--查询目录
                from.where(qSysPowerEntity.type.eq(ToolEnums.PowerTypeEnums.CATALOG));
            }
        }
        List<SysPowerVO> list = from.orderBy(qSysPowerEntity.sort.asc(), qSysPowerEntity.type.asc()).fetch();
        return PublicResult.queryOk(TreeNode.handleTree(list));
    }

    @Override
    public Map<String, Object> getUserMenuAndRouter(String name) {
        Map<String, Object> map = new HashMap<>(2);
        Predicate routerInfoQuery = qSysPowerEntity.type.eq(ToolEnums.PowerTypeEnums.MENU);
        Predicate menuInfoQuery = qSysPowerEntity.type.ne(ToolEnums.PowerTypeEnums.POWER);
        //处理超级用户
        if (!Objects.equals(CommonConst.SUPER_USER, name)) {
            Set<String> setId = new HashSet<>();
            // 查询用户权限的所有上级编号和上级编号集
            Set<String> collect = jpa.select(qSysPowerEntity.id, qSysPowerEntity.parentId, qSysPowerEntity.parentIds).from(qSysUserEntity)
                    .leftJoin(qSysUserRoleEntity).on(qSysUserEntity.id.eq(qSysUserRoleEntity.userId))
                    .leftJoin(qSysRoleEntity).on(qSysUserRoleEntity.roleId.eq(qSysRoleEntity.id))
                    .leftJoin(qSysRolePowerEntity).on(qSysRoleEntity.id.eq(qSysRolePowerEntity.roleId))
                    .leftJoin(qSysPowerEntity).on(qSysRolePowerEntity.powerId.eq(qSysPowerEntity.id))
                    .where(qSysUserEntity.name.eq(name)
                            .and(qSysUserEntity.state.eq(ToolEnums.StateEnums.ENABLE))
                            .and(qSysRoleEntity.state.eq(ToolEnums.StateEnums.ENABLE))).fetch()
                    .stream()
                    .map(tuple ->
                            Objects.equals(tuple.get(qSysPowerEntity.parentId), ToolConstant.TREE_DEF_PARENT) ? tuple.get(qSysPowerEntity.id) : tuple.get(qSysPowerEntity.id) + "," + tuple.get(qSysPowerEntity.parentIds)
                    ).collect(Collectors.toSet());
            /*
             * 没有查询到数据有两种情况
             * 1.本来就没权限
             * 2.有权限被禁用
             */
            if (CollectionUtils.isEmpty(collect)) {
                return null;
            }
            // 循环处理数据
            for (String s : collect) {
                String[] split = s.split(",");
                setId.addAll(Arrays.asList(split));
            }
            routerInfoQuery = ExpressionUtils.and(routerInfoQuery, qSysPowerEntity.id.in(setId));
            menuInfoQuery = ExpressionUtils.and(menuInfoQuery, qSysPowerEntity.id.in(setId));
        }

        // 查询出所有目录和菜单
        map.put("routerInfo", jpa.select(new SysPowerVO().initQBean(qSysPowerEntity))
                .from(qSysPowerEntity)
                .where(routerInfoQuery)
                .orderBy(qSysPowerEntity.sort.asc(), qSysPowerEntity.type.asc())
                .fetch());

        List<SysPowerVO> fetch = jpa.select(new SysPowerVO().initQBean(qSysPowerEntity))
                .from(qSysPowerEntity)
                .where(menuInfoQuery)
                .orderBy(qSysPowerEntity.sort.asc(), qSysPowerEntity.type.asc())
                .fetch();
        map.put("menuInfo", TreeNode.handleTree(fetch));
        return map;
    }

    @Override
    public PublicResult getPowerIdsByRoleId(String roleId) {
        return PublicResult.queryOk(jpa.select(qSysRolePowerEntity.powerId).from(qSysRolePowerEntity)
                .where(qSysRolePowerEntity.roleId.eq(roleId)).fetch());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PublicResult deleteByIds(List<SysPowerEntity> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return PublicResult.delFail("参数不能为空");
        }
        Set<String> delIds = new HashSet<>();
        for (SysPowerEntity entity : ids) {
            String id = entity.getId();
            delIds.add(id);
            delIds.addAll(jpa.select(qSysPowerEntity.id).from(qSysPowerEntity).where(qSysPowerEntity.parentIds.contains(id)).fetch());
        }
        //查询是否删除了权限
        boolean isDelPower = jpa.select(qSysPowerEntity.id).from(qSysPowerEntity)
                .where(qSysPowerEntity.id.in(delIds).and(qSysPowerEntity.type.eq(ToolEnums.PowerTypeEnums.POWER))).fetchCount() > 0;
        //删除权限
        jpa.delete(qSysPowerEntity).where(qSysPowerEntity.id.in(delIds)).execute();
        //删除角色关联权限
        jpa.delete(qSysRolePowerEntity).where(qSysRolePowerEntity.powerId.in(delIds)).execute();
        if (isDelPower) {
            updatePermission();
        }
        return PublicResult.delOk();
    }

    private Optional<PublicResult> validHandle(SysPowerEntity entity, ResultEnums resultEnums) {
        ToolEnums.PowerTypeEnums type = entity.getType();
        String id = entity.getId();
        String parentId = entity.getParentId();
        ToolEnums.PowerTypeEnums parentType = null;
        if (!Objects.equals(parentId, ToolConstant.TREE_DEF_PARENT)) {
            parentType = jpa.select(qSysPowerEntity.type).from(qSysPowerEntity).where(qSysPowerEntity.id.eq(parentId)).fetchOne();
            if (Objects.isNull(parentType)) {
                return Optional.of(PublicResult.resultEnums(resultEnums, "上级信息异常"));
            }
        }
        //获取上级下排序值，排除自己
        BooleanExpression query = qSysPowerEntity.parentId.eq(parentId).and(qSysPowerEntity.sort.eq(entity.getSort()));
        if (StrUtil.isNotBlank(id)) {
            query = query.and(qSysPowerEntity.id.ne(id));
        }
        boolean exists = mapper.exists(query);
        if (exists) {
            return Optional.of(PublicResult.resultEnums(resultEnums, "排序值已经存在"));
        }
        if (Objects.equals(ToolEnums.PowerTypeEnums.CATALOG, type)) {
            /*
             * 添加目录
             * 不能有上级
             */
            if (Objects.nonNull(parentType)) {
                return Optional.of(PublicResult.resultEnums(resultEnums, "不能有上级"));
            }
        } else if (Objects.equals(ToolEnums.PowerTypeEnums.MENU, type)) {
            /*
             * 添加菜单
             * 上级不能是菜单或者权限
             */
            if (Objects.equals(ToolEnums.PowerTypeEnums.MENU, parentType)
                    || Objects.equals(ToolEnums.PowerTypeEnums.POWER, parentType)) {
                return Optional.of(PublicResult.resultEnums(resultEnums, "上级不能是菜单或者权限"));
            }
        } else if (Objects.equals(ToolEnums.PowerTypeEnums.POWER, type)) {
            /*
             * 添加权限
             * 上级只能是菜单
             */
            if (!Objects.equals(ToolEnums.PowerTypeEnums.MENU, parentType)) {
                return Optional.of(PublicResult.resultEnums(resultEnums, "上级只能是菜单"));
            }

        }
        return Optional.empty();
    }

    @Override
    public PublicResult add(SysPowerEntity entity) {
        Optional<PublicResult> publicResult = validHandle(entity, ResultEnums.ADD_FAIL);
        if (!publicResult.isPresent()) {
            PublicResult add = super.add(entity);
            if (Objects.equals(entity.getType(), ToolEnums.PowerTypeEnums.POWER)) {
                updatePermission();
            }
            return add;
        } else {
            return publicResult.get();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PublicResult update(SysPowerEntity entity) {
        Optional<PublicResult> publicResult = validHandle(entity, ResultEnums.UPDATE_FAIL);
        // 修改时上级不能是自己
        String id = entity.getId();
        String parentId = entity.getParentId();
        if (Objects.equals(id, parentId)) {
            return PublicResult.updateFail("上级不能是自己");
        }
        // 如果修改时上级节点改变，子节点上级集也要进行调整
        SysPowerEntity oldEntity = jpa.select(qSysPowerEntity).from(qSysPowerEntity).where(qSysPowerEntity.id.eq(id)).fetchOne();
        if (Objects.isNull(oldEntity)) {
            return PublicResult.updateOk();
        }
        String oldParentId = oldEntity.getParentId();
        if (!Objects.equals(oldParentId, parentId)) {
            if (Objects.equals(parentId, ToolConstant.TREE_DEF_PARENT)) {
                // 修改成顶级 -- 将以前的上级编号+，替换成空
                mapper.replaceParentIds(oldParentId + ",", "", id);
            } else if (Objects.equals(oldParentId, ToolConstant.TREE_DEF_PARENT)) {
                // 以前是顶级 -- 在以前数据前追加现在上级编号+，
                mapper.appendBeforeParentIds(parentId + ",", id);
            } else {
                // 其他情况进行替换
                mapper.replaceParentIds(oldParentId, parentId, id);
            }
        }
        if (!publicResult.isPresent()) {
            PublicResult update = super.update(entity);
            /*
             * type == 权限的情况
             *      1.如果以前不是权限 -> 更新权限
             *      2.如果以前是权限,判断url是否修改,如果修改 -> 更新权限
             * type != 权限的情况
             * 1.以前是权限 -> 更新权限
             */
            if (Objects.equals(entity.getType(), ToolEnums.PowerTypeEnums.POWER)) {
                if (!Objects.equals(oldEntity.getType(), ToolEnums.PowerTypeEnums.POWER)) {
                    updatePermission();
                } else {
                    if (!Objects.equals(oldEntity.getUrl(), entity.getUrl())) {
                        updatePermission();
                    }
                }
            } else {
                if (Objects.equals(oldEntity.getType(), ToolEnums.PowerTypeEnums.POWER)) {
                    updatePermission();
                }
            }
            return update;
        } else {
            return publicResult.get();
        }
    }

    /**
     * 重新加载权限
     */
    public void updatePermission() {
        synchronized (shiroFilterFactoryBean) {
            AbstractShiroFilter shiroFilter;
            try {
                shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean.getObject();
            } catch (Exception e) {
                throw new RuntimeException("get ShiroFilter from shiroFilterFactoryBean error!");
            }
            PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter.getFilterChainResolver();
            DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver.getFilterChainManager();
            // 清空老的权限控制
            manager.getFilterChains().clear();
            shiroFilterFactoryBean.getFilterChainDefinitionMap().clear();
            Map<String, String> stringStringMap = CommonUtils.handleShiroPower(shiroFilterFactoryBean, mapper);
            shiroFilterFactoryBean.setFilterChainDefinitionMap(stringStringMap);
            // 重新构建生成
            Map<String, String> chains = shiroFilterFactoryBean.getFilterChainDefinitionMap();
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue().trim().replace(" ", "");
                manager.createChain(url, chainDefinition);
            }
            log.info("更新权限成功");
        }
    }

}
